//
//  ViewController.m
//  Block
//
//  Created by qianfeng01 on 15-4-24.
//  Copyright (c) 2015年 ndy. All rights reserved.
//

#import "ViewController.h"

typedef int (*FuncPoint)(int,int);

//给 block类型 void (^)(void)起别名 BlockTypy
typedef void (^BlockType)(void);

typedef int (^BlockType2)(int num1,int num2);

//int (*)(int,int) 起别名

//函数 就是一个有名的代码块
int add(int a, int b) {
    return a+b;
}
int sub(int a, int b) {
    return a-b;
}

@interface ViewController ()

@end

@implementation ViewController

{
    int _num;
}

- (void)testFuncPoint {
    //函数地址()
    int (*pFunc)(int,int) = add;
    int sum = pFunc(1,2);
    NSLog(@"sum:%d",sum);//3
    
    pFunc = sub;
    NSLog(@"%d",pFunc(1,2));//-1
    
    FuncPoint p = add;
    sum = p(1,2);
}

- (void)testBlock1 {
    //block  是就是一个代码块，可以理解为是一个匿名的代码块/匿名函数
    //代码块前 + ^
    //有参数 和 返回值类型
    /*
     ^ void (void){
     NSLog(@"我是block1");
     }();
     */
    
    //定义一个block 变量 保存block 代码块的地址
    //block 变量和 C语言的函数指针类似
    //myBlock是一个block 的变量
    //myBlock变量 存放的是= 右侧 block 代码块的一个地址
    void (^myBlock)(void) = ^ void (void) {
        NSLog(@"我是myBlock1");
    };
    //调用block--->block代码块的地址()/block变量名();
    myBlock();
}
//block 是有参数和返回值
- (void)testBlock2 {
    //1.无参无返回值的block
    
    void (^myBlock)(void) = ^ void  (void) {
        NSLog(@"我是一个MyBlock1");
    };
    //调用
    myBlock();
    //1.1无参无返回值的block void 可以省去不写
    void (^myBlock2)(void) = ^{
        NSLog(@"我是一个MyBlock2");
    };
    myBlock2();
    
    //2.有参数和返回值的block
    int (^myBlock3)(int,int) = ^int (int a,int b) {
        return a+b;
    };
    int sum = myBlock3(1,2);
    NSLog(@"sum:%d",sum);
    
    //block 可以认为就是 一种定义在函数内部的内嵌函数
    
    //写一个block 实现 求两个数的较大值
    
    int (^myBlock4)(int,int) = ^int (int a,int b) {
        return a > b ? a : b;
    };
    NSLog(@"%d",myBlock4(100,1000));
    
    //
}

- (void)testTypeDef {
    BlockType myBlock1 = ^{
        NSLog(@"myBlock1");
    };
    myBlock1();
    
    BlockType2 myBlock2 = ^ int (int a, int b) {
        return a+b;
    };
    NSLog(@"%d",myBlock2(1,1));
}
//把block 作为函数的参数
- (void)runBlock:(BlockType)myBlock {
    myBlock();
}

- (void)runBlock2:(BlockType2)myblock {
    
    NSLog(@"%d",myblock(1,2));
}

- (void)testBlock3 {
    [self runBlock:^{
        NSLog(@"hello,I am  a block");
    }];
    //传入block 代码块
    [self runBlock:^{
        NSLog(@"无参无返回值");
    }];
    
    BlockType myBlock  = ^ {
        NSLog(@"xxxx");
    };
    //传入block变量
    [self runBlock:myBlock];
    
    
    [self runBlock2:^int(int num1, int num2) {
        return num1-num2;
    }];
    
    
    [self runBlock2:^int(int num1, int num2) {
        return num1 > num2 ? num1:num2;
    }];
}
- (void)testSortedArr {
    NSMutableArray *arr = [[NSMutableArray alloc] initWithObjects:@"one",@"three",@"two",@"four", nil];
    //block 排序
    [arr sortUsingComparator:^NSComparisonResult(id obj1, id obj2) {
        return [obj1 compare:obj2] < 0;
    }];
    
    NSLog(@"arr:%@",arr);
    
    //遍历数组 也可以用block形式
    //第三个参数 含义 如果想中途退出枚举遍历 把第三个参数 写成*stop = YES
    [arr enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
        //obj遍历到得数组元素 idx 当前数组元素索引
        NSLog(@"obj- %@ idx = %ld",obj,idx);
        if (idx == 2) {
            //idx == 2的时候 退出枚举 相当于 循环中的break
            *stop = YES;//停止遍历
        }
        
    }];
}
//修改 函数内部变量
- (void)testBlock4 {
    int cnt = 1;
    
    __block int cnt2 = 1;//如果 block 内不要修改外部的局部变量 那么需要加__block 关键字
    //__block加上之后 再执行block的时候 会 把cnt2拷贝一份，使block 内部和外部 共享同一个数据
    
    void(^myBlock)(void) = ^ {
        //block 默认只能读 外面的局部变量
        NSLog(@"cnt_block:%d",cnt);
        cnt2++;
        _num = 10;//对象的实例变量可以直接修改
        NSLog(@"cnt2:_block:%d",cnt2);
    };//代码块 不调用 不会执行的
    
    NSLog(@"cnt2:%d",cnt2);//1
    //调用block  里面的代码 才会执行
    myBlock();//2
    NSLog(@"cnt2:%d",cnt2);//2
    
}
- (void)testBlockCopy {
    self.view.backgroundColor = [UIColor redColor];
    //
    void (^myBlock)(void) = ^{
        NSLog(@"myBlock");
    };
    //block 代码块 在oc中 相当于一个对象,这个block 会释放的
    //block 有些时候 不会立即调用 那么这时我们可以把block copy一下，而且block 只能copy
    //block 也要遵守黄金法则  copy 对应 release
    
    void (^newBlock)(void) = [myBlock copy];
    newBlock();
    
}


- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end
